/*
 * ResValue.cpp
 *
 *  Created on: May 26, 2018
 *      Author: hp
 */

#include <stdlib.h>
#include <stdio.h>

#include "ResValue.h"
#include "ResStringPool.h"

ResValue::ResValue() {
}

ResValue::ResValue(const ResStringPool& string_pool, Res_value value) {
	if (value.dataType == Res_value::TYPE_STRING)
		set_string(string_pool.get(value.data));
	else
		_value = value;
}

ResValue& ResValue::operator=(const ResValue& val) {
	_value = val._value;

	if (val._value.dataType == Res_value::TYPE_STRING)
		_string = strdup(val._string);

	return *this;
}

ResValue::~ResValue() {
	free((void*) _string);
}

void ResValue::set_bool(bool val) {
	_value.dataType = Res_value::TYPE_INT_BOOLEAN;
	_value.data = val;
}

void ResValue::set_string(const char* val) {
	_value.dataType = Res_value::TYPE_STRING;
	// We don't know the stringpool value of this string yet.
	_string = strdup(val);
}

void ResValue::set_int(int32_t val) {
	_value.dataType = Res_value::TYPE_INT_DEC;
	_value.data = val;
}

void ResValue::set_float(float val) {
	_value.dataType = Res_value::TYPE_FLOAT;
	*(float*)&_value.data = val;
}

void ResValue::set_hex(int32_t val) {
	_value.dataType = Res_value::TYPE_INT_HEX;
	_value.data = val;
}

void ResValue::set_reference(uint32_t val) {
	_value.dataType = Res_value::TYPE_REFERENCE;
	_value.data = val;
}

const char* ResValue::to_string() {
	char* data = nullptr;
	uint32_t size;

	switch (_value.dataType) {
	case Res_value::TYPE_REFERENCE:
		size = snprintf(nullptr, 0, "Reference: 0x%08X", _value.data);
		++size;
		data = (char*) malloc(size);
		snprintf(data, size, "Reference: 0x%08X", _value.data);
		break;
	case Res_value::TYPE_INT_DEC:
		size = snprintf(nullptr, 0, "%i", _value.data);
		++size;
		data = (char*) malloc(size);
		snprintf(data, size, "%i", _value.data);
		break;
	case Res_value::TYPE_INT_HEX:
		size = snprintf(nullptr, 0, "0x%02X", _value.data);
		++size;
		data = (char*) malloc(size);
		snprintf(data, size, "0x%02X", _value.data);
		break;
	case Res_value::TYPE_FLOAT:
		size = snprintf(nullptr, 0, "%g", *(const float*)&_value.data);
		++size;
		data = (char*) malloc(size);
		snprintf(data, size, "%g", *(const float*)&_value.data);
		break;
	case Res_value::TYPE_STRING:
		data = strdup(_string);
		break;
	case Res_value::TYPE_INT_BOOLEAN:
		if (_value.data) {
			data = (char*) malloc(6);
			snprintf(data, 6, "true");
		} else {
			data = (char*) malloc(7);
			snprintf(data, 7, "false");
		}
		break;
	default:
		data = (char*) malloc(20);
		snprintf(data, 20, "Unknown type %i", _value.dataType);
	}

	return data;
}

Res_value ResValue::serialize(ResStringPool& stringpool) {
	if (_value.dataType == Res_value::TYPE_STRING)
		_value.data = stringpool.put(_string).index;

	return _value;
}
